#include "Terrain.h"
#include "Transformation.h"
#include "Camera.h"
#include "Scene.h"
#include "Logger.h"
#include "Exception.h"

using namespace game_engine;
using namespace game_engine::components;
using namespace game_engine::tile_engine;
using namespace game_engine::utils;

///////////////////////////////////////////////////////////////////////////////
// Constructors and Destructors
///////////////////////////////////////////////////////////////////////////////

Terrain::Terrain(void)
    : Component(), tileInfoFile(), tileTextureFile(), tileWorld()
{
    type = "Terrain";
}

Terrain::Terrain(GameObject *obj, const string &infoFile, const string &textFile)
    : Component(obj), tileInfoFile(infoFile), tileTextureFile(textFile), tileWorld()
{
    type = "Terrain";
}

Terrain::~Terrain(void)
{
}

///////////////////////////////////////////////////////////////////////////////
// Other public methods
///////////////////////////////////////////////////////////////////////////////

void Terrain::initialize(void) throw(...)
{
    Size resolution = (object->getScene())->getResolution();
    tileWorld.setWorldWidth(resolution.getWidth());
    tileWorld.setWorldHeight(resolution.getHeight());

    // Read descriptor
    try
    {
        tileWorld.loadLevel(tileInfoFile, tileTextureFile);
    } catch (exception &e)
    {
        string msg("Error initializing terrain component : ");
        msg.append(e.what());
        Logger::FATAL(GAMEENGINE_LOG, msg);
        throw RuntimeException(msg);
    }
}

//void Terrain::update(void)
//{
//}

void Terrain::render(void) throw(...)
{
    // Get the scene's active camera
    GameObject *cam = (object->getScene())->getActiveCamera();
    if (cam == NULL)
    {
        string err("No active camera defined in current scene");
        throw NullPointerException(err);
    }

    // Get active camera position and field of view
    Transformation *camTransf;
    Camera *c;
    try
    {
        camTransf = dynamic_cast<Transformation*> 
            (cam->getComponent("Transformation"));
        c = dynamic_cast<Camera*>(cam->getComponent("Camera"));
    } catch (exception &e)
    {
        string err("Error rendering Terrain component : ");
        err.append(e.what());
        throw RuntimeException(err);
    }

    // Draw the tile world
    Point cameraPosition(camTransf->getXPosition(), camTransf->getYPosition());
    Rect view(c->getView());
    tileWorld.draw(cameraPosition, view);
}

///////////////////////////////////////////////////////////////////////////////
// Getters
///////////////////////////////////////////////////////////////////////////////

const Size Terrain::getDimensions(void) const
{
    return Size(tileWorld.getTileWidth() * tileWorld.getWorldWidth(),
        tileWorld.getTileHeight() * tileWorld.getWorldHeight());
}

const vector<Tile*> Terrain::getSurroundingTiles(const Point &worldPosition) const
{
    return tileWorld.surroundingTiles(worldPosition);
}

///////////////////////////////////////////////////////////////////////////////
// Setters
///////////////////////////////////////////////////////////////////////////////

void Terrain::setTileInfoFile(const string &file)
{
    tileInfoFile = file;
}

void Terrain::setTileTextureFile(const string &file)
{
    tileTextureFile = file;
}
